Using Visual Studio with Webpack for Angular Development

Introduction

With the release of Angular 2 and ASP.NET Core in 2016, the two technologies have become a common pair for .Net web developers. The .NET Core’s platform agnostic ability has made it more appealing even for the non .Net developers. Moreover, Microsoft has been pushing hard to reach this outside market and introduced Visual Studio Code, a platform agnostic IDE that has some of the powerful features of the heavier Visual Studio but the ability to work outside the traditional .Net / IIS environment, such as with NodeJS. There are numerous courses and examples of starting Angular 2 with .Net Core and using Visual Studio Code.

Unfortunately, with the introduction of these new technologies and tools, the online community has quickly left and forgotten some of the older tools that have yet to catch up, such as Visual Studio 2015. Moreover, with the recent release of Visual Studio 2017 and it’s new abilities and templates for web development, especially with that of TypeScript and Angular, we have found it difficult to find much support or recent examples for Visual Studio 2015.

Our project was based on Visual Studio 2015 and the 2017 version was not an option for us during development. Also, our backend and database services relied heavily on the traditional .Net framework (v4.6) and so upgrading to the newer .NET Core was not an option. However, we needed to use the latest Angular framework (v2.4) for frontend development and wanted to have that project in the same Visual Studio solution as our backend projects.

This document covers the steps we took to setup the Angular project in Visual Studio 2015 and how we got it to work with the traditional .Net Framework (v4.6) and using Web API (v2).  To protect some sensitive information in our solution, this document uses a Sample solution we created, which mimics our original solution minus the sensitive parts. This sample solution has two projects, one is the Web API backend and the second is the Angular front end. This sample solution could be used as a starting point for future projects using these same technologies.

The sample solution source repository is located here:
https://github.com/johnlee/Widgets.NG2

 

API

The backend API project of our sample solution is the standard Visual Studio 2015 Web API project template. We start with this template and add just a few changes, which are outlined below:

  • Use the default Web API Help Pages and set the XML file at root of solution
  • Make the Help Pages the only web controller
  • Add the following api controllers / endpoints
    • Products
    • Users
    • Orders
  • Setup models for the above controllers
  • Enable CORS

 

Below is a sample project structure with the new controllers, models and Help Pages documentation XML file. The API controllers use the standard methods created for you when selecting the Visual Studio’s API Controller template on creation.

In the API sample project, we wanted to have a single web page served, which would be the out-of-the-box Help Pages provided by Visual Studio when using the Web API project template. This help page relies on an XML file that is generated during build time. We wanted this XML file to reside on the root of the project. This can be done by configuring the “Areas\HelpPage\App_Start\HelpPageConfig.cs” file:

We also wanted to make sure that no other web page would be served. So we locked down the web routing so that everything would be automatically redirected to the Help Page controller. This is done on the RouteConfig.cs:

Finally we wanted to create some sample API controllers that fed our front end some sample data. We generated some mock data, which you can find this in the models. The API controllers only have GET methods for this sample project.

At this point you can see that the API project is only serving the help web page and no other front end pages. The help page is being served by Visual Studio’s IIS EXPRESS server. The application front end will be in the Angular Web project and it will be served by a separate web server. We will discuss this in the next section. However, since the front end app is being served in a different URL than the backend, we will need to enable CORS on our API project. This is shown in the next section.

 

Enabling CORS

The enabling of CORS is documented in the following links below. We followed the procedure there and this is what the WebApiConfig.cs resulted in:

https://docs.microsoft.com/en-us/aspnet/web-api/overview/security/enabling-cross-origin-requests-in-web-api

https://msdn.microsoft.com/en-us/magazine/dn532203.aspx

 

At this point the API project is complete and ready to run. We can run it in Visual Studio with no debugging (CTRL – F5). We will now move on to the front end app project.

 

Web

In our front end project we are using Visual Studio 2015 with Typescript 2.2, Angular (v2.4) and NodeJS (v7+). At the time, there were no built-in Visual Studio templates for this type of project. Matter of fact, TypeScript was not part of the Visual Studio 2015 installation and so had to be installed separately. To run our sample web project, the following needs to be installed in Visual Studio 2015.

TypeScript for Visual Studio 2015 (as of this document date we use v2.2)

https://www.microsoft.com/en-us/download/details.aspx?id=48593

NPM Task Runner for Visual Studio 2015

https://marketplace.visualstudio.com/items?itemName=MadsKristensen.NPMTaskRunner

WebPack Task Runner for Visual Studio 2015

https://marketplace.visualstudio.com/items?itemName=MadsKristensen.WebPackTaskRunner

The Task Runners are great plugins that can be used to run and monitor NPM scripts through Visual Studio. Without these Task Runners, we would need to execute the NPM scripts outside of Visual Studio through a command prompt or other some CLI shell.

 

 

Angular IO’s Cookbook for Visual Studio 2015

As the Angular 2 alpha release became available, the Angular team created a cookbook for setting it up in Visual Studio 2015. We followed this article initially but later found the Quick Starter Pack to be using libraries we did not want – such as the web server, JS testing framework (Karma) which requires the Jasmine platform and a variety of other libraries. It also did not include a bundler and other build tools we were looking for.

For reference though, the Angular 2 on Visual Studio 2015 cookbook can be found here:

https://angular.io/docs/ts/latest/cookbook/visual-studio-2015.html

 

 

Our Starter Template

We explored a variety of tools and libraries that could be used with Angular to create the development environment and build packages for deployment. We looked at the common task runner tools like Grunt and Gulp, as well as some custom scripting options we could do in Node. However, the tool we ended up going with was WebPack. This provided a rich set of functionalities and we found a substantial amount of support and documentation from the online community. Unfortunately though, much of the documentation were based on other platforms, unlike our Visual Studio 2015 solution. So we had to do some mixing and matching to get it to work with our Visual Studio 2015 solution.

In the sections below we are going to review some of the libraries we use and how we have them configured. However, we don’t go in-depth as to how each of these tools and libraries work. We instead provide reference links to that information and let the creators give a far better presentation on “how-it-works”.

The remainder of this document will focus on:

  • Overview of WebPack
  • How we have WebPack setup in our project
    • json
    • json
    • config
    • json

 

Overview of WebPack

WebPack is a build tool used to do a variety of tasks for front end web development. Such tasks as compile, bundle, minify – all of which can be configured and customized by the developer. The full documentation with guides can be found on the official WebPack site shown below.

https://webpack.js.org/guides/

To understand the WebPack tool and it’s objectives, we can observe the core concepts outlined in this article below:

https://webpack.js.org/concepts/

Being that our front end Angular app was written in TypeScript and divided into multiple modules, the first thing we needed was a compiler. WebPack does this by building a dependency graph of the whole application. It follows the Angular import/export modules (WebPack can also traverse ES2015 modules), starting with the root app.module. With this graph, WebPack can be configured to build into different environments, such as development vs production, each environment having different tasks. As discussed in the concepts article above, this is all done through a variety of loaders and plugins in WebPack.

 

Loaders

Loaders are Javascript objects that perform transformations on the source code. In our project we have several types of loaders that handle different file types. For example, we have a file loader that bundles binary files like images and fonts, as well as a raw loader for html files. And we have a set of loaders that work with our Angular TypeScript and Javascript files. All these loaders come from third-party libraries, which can be seen in the webpack.config file. We will describe this in more detail in the sections below.

Plugins

Plugins are Javascript objects that can be applied during the WebPack compiler. In our project we use WebPack built-in plugins to do various code cleanup and setup of the final deployment folder. You can find these in the webpack.config files, which we’ll cover in more detail in the sections below.

Code Splitting

One of main tasks WebPack performs is the splitting of the application code into separate bundles. These bundles can be organized to specific functions where only the needed functions are loaded on demand. This significantly reduces the client load time.

In WebPack, the resulting code splits can be seen in what are called ‘chunk’ files. These can be divided up depending on dependencies or even file types. For example, you may want to have a separate bundle for styling (css) vs the application code (js). By default though, WebPack embeds styling code into the HTML and JS files. In our project, this is the route we took and so our style.css file is embedded into the index.html file during WebPack build.

You can read more on code splitting here:

https://webpack.js.org/guides/code-splitting/

In our sample project you will find 6 bundle files. The vendor and polyfills bundle files cover most of the third-party libraries whereas the app.bundle has our main Angular app module as well as the core Angular libraries. The 4 additional chunk files (0 – 4) are each of the Angular modules we have in our app. You can see that by dividing these chunks into the separate modules, the client doesn’t need to load everything at once. Instead they only load the module needed on demand.

To see a full graph of dependencies, WebPack has the following online tool. Simply load the stats.json file that is generated at the root of our Web project. Through this tool you can get a visual graph of all the libraries and chunks.

https://webpack.github.io/analyse

 

Hot Module Replacement (HMR)

One of our favorite features WebPack is the Hot Module Replacement (HMR). It basically watches the project files for any changes. As soon as something changes, it does and incremental compilation (of only those changes) and then pushes the changes out to the browser. As such, on the browser we will be able to see our code changes show up immediately after we make them. No need to do a rebuild or even a page refresh.

You can read more about this feature here:

https://webpack.js.org/concepts/hot-module-replacement

 

 

HMR vs Watch

When we first created our front end project in Visual Studio 2015 we were trying to use the IIS Express web server with WebPack. At the time we didn’t know about the WebPack dev server and HMR ☹. In this initial solution we ran WebPack with the “watch” command. This makes WebPack monitor the Angular files and emit changes to the file system real time, much like HMR. So for example, we setup WebPack to emit the files to a “dist” folder which IIS was serving out of. The problem with this approach was that the browser would not pickup the changes from IIS until you did a refresh (F5). Though one may call us lazy, we easily favored the HMR process over this once we learned about it.

http://stackoverflow.com/questions/38089785/webpack-watch-vs-hot-whats-the-difference

 

 

Ahead of Time Compilation

Traditionally, as browsers open a web page it will download the page assets (HTML, JS, CSS) and process all the scripts at the initial load. Being that Angular uses templates and components with various bindings in between, the Angular code needs an additional compilation step. The browser is able to compile this by also downloading an Angular compiler at initial load. This is known as Just-in-Time (JIT) compilation.

Its not hard to see the flaws with this process. First, we are putting additional load on the browser by making it compile the code and second, we are requiring more data transfer by sending the Angular compiler. This has some negative affects to performance and ultimately – the user experience.

To avoid this performance hit, it is recommended to implement Ahead of Time compilation (AoT). In this approach the code is compiled at build time and the browser only gets the compiled code. This removes the need for the browser to download the Angular compiler and do the compilation. This has significant improvements to performance. Details on the performance gains and how the Angular compiler works can be seen in the following video presented by the Angular team:

https://www.youtube.com/watch?v=kW9cJsvcsGo

For more information on AoT compilation please refer to this article on Angular’s site:

https://angular.io/docs/ts/latest/cookbook/aot-compiler.html

Our sample project implements AoT compilation for production builds. We do this by having a second tsconfig-aot.json config file and a second WebPack entry point main-aot.ts file. We show details of this config file in the tsconfig.json section below. Some of the key differences in the tsconfig-aot.json are:

  • No use of source maps à this is more for debugging purposes and not needed in a production environment
  • Module is set to es2015 à this is important for Tree Shaking, as discussed in the section below
  • angularCompilerOptions – genDir à this tells the compiler to put the resulting output files into a separate directory

 

 

Angular Lazy Loader

One of the principals of Web Performance Optimization is to avoid having the client load unnecessary files. In Angular, we can achieve this through what is called Lazy Loading. Since Angular uses a modular architecture, we have divided our application into feature modules. At the initial load of our application (the dashboard page), it is unnecessary to load all of these feature modules. So instead, we’ve incorporated Lazy Loading by having only the selected feature be loaded on demand. WebPack is able to do this for us by splitting the resulting bundle files based on modules. So at initial load, the user does not need to load all the bundle files.

In Angular, this is mostly done through the routing mechanism. You can see our feature modules divided up in the main app.routing file as shown below:

For more information on Lazy loading refer to this article:

https://github.com/damienbod/AngularWebpackVisualStudio/blob/master/LAZY_LOADING.md

 

 

Sample starter templates we sourced our project from

Using Visual Studio 2015 with WebPack for .NET Core and Angular

http://blog.stevensanderson.com/2016/10/04/angular2-template-for-visual-studio/

Using WebPack to build Angular

https://www.illucit.com/blog/2016/06/angular2-npm-webpack/

Using Visual Studio 2017 with WebPack for .NET Core and Angular

https://github.com/damienbod/AngularWebpackVisualStudio

Barebones Angular2 with WebPack and Unit Testing by Jasmine

https://github.com/preboot/angular-webpack

 

Setting up WebPack

NodeJS

Before we go any further with using WebPack, it is important to note that all libraries used in the front end app, including WebPack, is downloaded via NPM. In order to use NPM we must have NodeJS installed. You should note that NodeJS can be installed multiple times on a system. For example, it can be installed through Visual Studio, and in the case of our team, we also had a version installed for Git. This is important to note because if you need a specific version of Node, the one Visual Studio is using may not be the right one. We had this problem on our team and needed to configure the External Tools path so it picked up the correct version.

More information about this can be found at the link below but we’ve included a snippet of the instructions as well.

https://github.com/damienbod/AngularWebpackVisualStudio

Node Path in Visual Studio

The installed nodejs on your system needs to be used inside Visual Studio and not VS one. You need to set the path of you node before the VS node.

In Visual Studio Tools/Options/Projects and Solutions/Web Package Management/External Web Tools

More the $(Path) option above the Visual Studio one.

Also see:

https://github.com/madskristensen/NpmTaskRunner/issues/46

 

Setting up package.json

Package.json (devDependencies vs Dependencies)

  • Dependencies are libraries required to run (Production and Dev mode)
  • devDependencies are only required to develop
    • Transpilation / Compilation
    • Minification
    • Bundling
    • Linting
    • Unit Testing
    • WebPack Loaders, Plugins
  • Scripts are npm commands/scripts that can be run to perform some task, such as running the webpack build or webpack-dev-server

Our package.json is shown below using Angular 2.4 and WebPack 2.2. All other libraries are compliant with these versions.

 

Setting up webpack.config

As discussed in the previous section on AoT compilation, our sample project has two separate build profiles. One is for the development environment using webpack-dev-server and the second is for production environment which uses the AoT compilation process. Our webpack.config calls the different profiles based on the Node environment variable – NODE_ENV.

There are some overlap in the webpack.dev and webpack.prod config files, in particular with the calls to loaders and plugins. However, you will see that our webpack.prod config includes a minification step whereas our webpack.dev calls devtools and devserver. Both configs have the same entry and output points (but the webpack.prod will be following the tsconfig-aot.config compilation as described in the next section).

 

Setting up tsconfig.json

As discussed in the prior section about AoT compilation, there are two tsconfig.json files. One is for JIT (just in time compile) which is the tsconfig.json file. The second is for AOT (ahead of time compile) which is the tsconfig-aot.json. As noted in the prior section, the main differences are:

  • No use of source maps à this is more for debugging purposes and not needed in a production environment
  • Module is set to es2015 à this is important for Tree Shaking, as discussed in the section below
  • angularCompilerOptions – genDir à this tells the compiler to put the resulting output files into a separate directory

 

Setting up tsling.json

Our sample project uses linting for the TypeScript code. This is configured through the tslint.config file. This file basically sets binary flags for different code style / rules that tslint should watch for. Please refer to the following link for more information on using tslint:

 

 

References

Some other random (or not so random) links and information for reference.

 

Angular vs Vue vs React

All had significant presence in 2016, with Vue and Angular2 being initially released in 2016

 

Source Maps

http://blog.teamtreehouse.com/introduction-source-maps

 

Tree Shaking

Ability to remove any code that we are not actually using in our application from the final bundle, such as unused functions, variables, etc. It reduces the final footprint of the application. It can also remove non-essential code, specifically for a production environment. For example, removing “console.log” code throughout the application.

http://blog.rangle.io/optimize-your-angular2-application-with-tree-shaking/

 

AoT

https://medium.com/@isaacplmann/getting-your-angular-2-library-ready-for-aot-90d1347bcad

http://blog.mgechev.com/2016/08/14/ahead-of-time-compilation-angular-offline-precompilation/

 

Setup OWIN to use a static WWWROOT folder like .NET CORE

http://stackoverflow.com/questions/36294188/using-a-wwwroot-folder-asp-net-5-style-in-asp-net-4-5-project

 

ASP.NET Core and Angular starter templates

https://github.com/FabianGosebrink/ASPNETCore-Angular-Webpack-StarterTemplate

https://offering.solutions/blog/articles/2016/08/27/how-to-set-up-angular-2-and-webpack-in-visual-studio-with-asp-net-core/

https://github.com/damienbod/Angular2WebpackVisualStudio

 

Web Performance Optimization

  • Minification
  • Bundling
  • Compression
  • Tree Shaking
  • Ahead of Time (AoT) compile

 

Advantages of SPA

  • Performance (single load, majority of work happens on client with no need to go over wire for each page)
  • Responsive
  • Decouples front and back end, allows support for a variety of front end clients (mobile, web, etc)
  • Overall user experience